//检测日期是否有效
const isDateValid = (...val) => !Number.isNaN(new Date(...val).valueOf());

isDateValid("December 17, 1995 03:24:00");  // true

// 计算两个日期之间的间隔
const dayDif = (date1, date2) => Math.ceil(Math.abs(date1.getTime() - date2.getTime()) / 86400000)
    
dayDif(new Date("2021-11-3"), new Date("2022-2-1"))  // 90

// 找日期位于一年中的第几天
const dayOfYear = (date) => Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);

dayOfYear(new Date());   // 307
// 时间格式化
const timeFromDate = date => date.toTimeString().slice(0, 8);
    
timeFromDate(new Date(2021, 11, 2, 12, 30, 0));  // 12:30:00
timeFromDate(new Date());  // 返回当前时间 09:00:00

// 字符串首字母大写
const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)

capitalize("hello world")  // Hello world
// 翻转字符串
const reverse = str => str.split('').reverse().join('');

reverse('hello world');   // 'dlrow olleh'
// 随机字符串
const randomString1 = () => Math.random().toString(36).slice(2);

randomString1();
// 截断字符串
const truncateString = (string, length) => string.length < length ? string : `${string.slice(0, length - 3)}...`;

truncateString('Hi, I should be truncated because I am too loooong!', 36)   // 'Hi, I should be truncated because...'
// 去除字符串中的HTML
const stripHtml = html => (new DOMParser().parseFromString(html, 'text/html')).body.textContent || '';
// 从数组中移除重复项
const removeDuplicates = (arr) => [...new Set(arr)];

console.log(removeDuplicates([1, 2, 2, 3, 3, 4, 4, 5, 5, 6]));
// 判断数组是否为空
const isNotEmpty = arr => Array.isArray(arr) && arr.length > 0;

isNotEmpty([1, 2, 3]);  // true
// 合并两个数组
const merge1 = (a, b) => a.concat(b);

const merge2 = (a, b) => [...a, ...b];
// 判断一个数是奇数还是偶数
const isEven = num => num % 2 === 0;

isEven(996); 
// 获得一组数的平均值
const average = (...args) => args.reduce((a, b) => a + b) / args.length;

average(1, 2, 3, 4, 5);   // 3

// 获取两个整数之间的随机整数
const random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);

random(1, 50);

// 指定位数四舍五入
const round = (n, d) => Number(Math.round(n + "e" + d) + "e-" + d)

round(1.005, 2) //1.01
round(1.555, 2) //1.56
// 将RGB转化为十六机制
const rgbToHex = (r, g, b) => "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);

rgbToHex(255, 255, 255);  // '#ffffff'

// 获取随机十六进制颜色
const randomHex = () => `#${Math.floor(Math.random() * 0xffffff).toString(16).padEnd(6, "0")}`;

randomHex();

// 复制内容到剪切板
const copyToClipboard = (text) => navigator.clipboard.writeText(text);

copyToClipboard("Hello World");

// 清除所有cookie
const clearCookies = document.cookie.split(';').forEach(cookie => document.cookie = cookie.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date(0).toUTCString()};path=/`));

// 获取选中的文本
const getSelectedText = () => window.getSelection().toString();

getSelectedText();

// 检测是否是黑暗模式
const isDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches

console.log(isDarkMode)

// 滚动到页面顶部
const goToTop = () => window.scrollTo(0, 0);

goToTop();

// 判断当前标签页是否激活
const isTabInView = () => !document.hidden; 

// 判断当前是否是苹果设备
const isAppleDevice = () => /Mac|iPod|iPhone|iPad/.test(navigator.platform);

isAppleDevice();

// 是否滚动到页面底部
const scrolledToBottom = () => document.documentElement.clientHeight + window.scrollY >= document.documentElement.scrollHeight;

// 重定向到一个URL
const redirect = url => location.href = url

redirect("https://www.google.com/")

// 打开浏览器打印框
const showPrintDialog = () => window.print()

// 随机布尔值
const randomBoolean = () => Math.random() >= 0.5;

randomBoolean();

// 变量交换
[foo, bar] = [bar, foo];

// /获取变量的类型

const trueTypeOf = (obj) => Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();

trueTypeOf('');     // string
trueTypeOf(0);      // number
trueTypeOf();       // undefined
trueTypeOf(null);   // null
trueTypeOf({});     // object
trueTypeOf([]);     // array
trueTypeOf(0);      // number
trueTypeOf(() => {});  // function

// 华氏度和摄氏度之间的转化
const celsiusToFahrenheit = (celsius) => celsius * 9/5 + 32;
const fahrenheitToCelsius = (fahrenheit) => (fahrenheit - 32) * 5/9;

celsiusToFahrenheit(15);    // 59
celsiusToFahrenheit(0);     // 32
celsiusToFahrenheit(-20);   // -4
fahrenheitToCelsius(59);    // 15
fahrenheitToCelsius(32);    // 0


// 检测对象是否为空
const isEmpty = obj => Reflect.ownKeys(obj).length === 0 && obj.constructor === Object;




/**
 * tools函数
 */

/**
 * 数字操作
 */
//生成指定范围随机数
export const randomNum = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
//数字千分位分隔
export const format = (n) => {
    let num = n.toString();
    let decimals = '';
    // 是否有小数
    num.indexOf('.') > -1 ? decimals = num.split('.')[1] : decimals;
    let len = num.length;
    if (len <= 3) {
        return num;
    } else {
        let temp = '';
        let remainder = len % 3;
        decimals ? temp = '.' + decimals : temp;
        if (remainder > 0) { // 不是3的整数倍
            return num.slice(0, remainder) + ',' + num.slice(remainder, len).match(/\d{3}/g).join(',') + temp;
        } else { // 3的整数倍
            return num.slice(0, len).match(/\d{3}/g).join(',') + temp; 
        }
    }
}
/**
 * 数组操作
 */
//数组乱序
export const arrScrambling = (arr) => {
    for (let i = 0; i < arr.length; i++) {
      const randomIndex = Math.round(Math.random() * (arr.length - 1 - i)) + i;
      [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
    }
    return arr;
}
//数组扁平化
export const flatten = (arr) => {
    let result = [];
  
    for(let i = 0; i < arr.length; i++) {
      if(Array.isArray(arr[i])) {
        result = result.concat(flatten(arr[i]));
      } else {
        result.push(arr[i]);
      }
    }
    return result;
  }
  //数组中获取随机数
  export const sample = arr => arr[Math.floor(Math.random() * arr.length)];

  /**
   * 字符串操作
   */
  //生成随机字符串
  export const randomString = (len) => {
    let chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz123456789';
    let strLen = chars.length;
    let randomStr = '';
    for (let i = 0; i < len; i++) {
        randomStr += chars.charAt(Math.floor(Math.random() * strLen));
    }
    return randomStr;
};
 //字符串首字母大写  
 export const fistLetterUpper = (str) => {
    return str.charAt(0).toUpperCase() + str.slice(1);
};
//手机号中间四位变成*
export const telFormat = (tel) => {
    tel = String(tel); 
  return tel.substr(0,3) + "****" + tel.substr(7);
};
// 骆驼命名转换成短横线命名
export const getKebabCase = (str) => {
    return str.replace(/[A-Z]/g, (item) => '-' + item.toLowerCase())
}
//短横线命名转换成骆驼命名
export const getCamelCase = (str) => {
    return str.replace( /-([a-z])/g, (i, item) => item.toUpperCase())
}
// 全角转换为半角
export const toCDB = (str) => {
    let result = "";
    for (let i = 0; i < str.length; i++) {
      code = str.charCodeAt(i);
      if (code >= 65281 && code <= 65374) {
        result += String.fromCharCode(str.charCodeAt(i) - 65248);
      } else if (code == 12288) {
        result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32);
      } else {
        result += str.charAt(i);
      }
    }
    return result;
  }
//半角转换为全角
export const toDBC = (str) => {
    let result = "";
    for (let i = 0; i < str.length; i++) {
      code = str.charCodeAt(i);
      if (code >= 33 && code <= 126) {
        result += String.fromCharCode(str.charCodeAt(i) + 65248);
      } else if (code == 32) {
        result += String.fromCharCode(str.charCodeAt(i) + 12288 - 32);
      } else {
        result += str.charAt(i);
      }
    }
    return result;
  }
/**
 * 格式转化
 * 
 * */  
//数字转化为大写金额
export const digitUppercase = (n) => {
    const fraction = ['角', '分'];
    const digit = [
        '零', '壹', '贰', '叁', '肆',
        '伍', '陆', '柒', '捌', '玖'
    ];
    const unit = [
        ['元', '万', '亿'],
        ['', '拾', '佰', '仟']
    ];
    n = Math.abs(n);
    let s = '';
    for (let i = 0; i < fraction.length; i++) {
        s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
    }
    s = s || '整';
    n = Math.floor(n);
    for (let i = 0; i < unit[0].length && n > 0; i++) {
        let p = '';
        for (let j = 0; j < unit[1].length && n > 0; j++) {
            p = digit[n % 10] + unit[1][j] + p;
            n = Math.floor(n / 10);
        }
        s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
    }
    return s.replace(/(零.)*零元/, '元')
        .replace(/(零.)+/g, '零')
        .replace(/^整$/, '零元整');
};
//数字转化为中文数字
export const intToChinese = (value) => {
    const str = String(value);
    const len = str.length-1;
    const idxs = ['','十','百','千','万','十','百','千','亿','十','百','千','万','十','百','千','亿'];
    const num = ['零','一','二','三','四','五','六','七','八','九'];
    return str.replace(/([1-9]|0+)/g, ( $, $1, idx, full) => {
       let pos = 0;
       if($1[0] !== '0'){
         pos = len-idx;
         if(idx == 0 && $1[0] == 1 && idxs[len-idx] == '十'){
              return idxs[len-idx];
         }
            return num[$1[0]] + idxs[len-idx];
       } else {
            let left = len - idx;
            let right = len - idx + $1.length;
            if(Math.floor(right / 4) - Math.floor(left / 4) > 0){
                 pos = left - left % 4;
            }
            if( pos ){
                 return idxs[pos] + num[$1[0]];
            } else if( idx + $1.length >= len ){
                 return '';
            }else {
                 return num[$1[0]]
            }
       }
      });
   }
   /**
    * 操作存储
    */
//存储loalStorage
export const loalStorageSet = (key, value) => {
    if (!key) return;
    if (typeof value !== 'string') {
        value = JSON.stringify(value);
    }
    window.localStorage.setItem(key, value);
};
//获取localStorage
export const loalStorageGet = (key) => {
    if (!key) return;
    return window.localStorage.getItem(key);
};
//删除localStorage
export const loalStorageRemove = (key) => {
    if (!key) return;
    window.localStorage.removeItem(key);
};
//存储sessionStorage
export const sessionStorageSet = (key, value) => {
    if (!key) return;
    if (typeof value !== 'string') {
    		value = JSON.stringify(value);
    }
    window.sessionStorage.setItem(key, value)
};
//获取sessionStorage
export const sessionStorageGet = (key) => {
    if (!key) return;
  return window.sessionStorage.getItem(key)
};
//删除sessionStorage
export const sessionStorageRemove = (key) => {
    if (!key) return;
  window.sessionStorage.removeItem(key)
};
/**
 * 操作cookie
 */
//设置cookie
export const setCookie = (key, value, expire) => {
    const d = new Date();
    d.setDate(d.getDate() + expire);
    document.cookie = `${key}=${value};expires=${d.toUTCString()}`
};
//读取cookie
export const getCookie = (key) => {
    const cookieStr = unescape(document.cookie);
       const arr = cookieStr.split('; ');
       let cookieValue = '';
       for (let i = 0; i < arr.length; i++) {
           const temp = arr[i].split('=');
           if (temp[0] === key) {
               cookieValue = temp[1];
               break
       }
    }
    return cookieValue
};
//删除cookie
export const delCookie = (key) => {
    document.cookie = `${encodeURIComponent(key)}=;expires=${new Date()}`
};
/**
 * 格式校验
 */
// 校验身份证号码
export const checkCardNo = (value) => {
    let reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
    return reg.test(value);
};
//校验是否包含中文
export const haveCNChars = (value) => {
    return /[\u4e00-\u9fa5]/.test(value);
}
//校验是否为中国大陆的邮政编码
export const isPostCode = (value) => {
    return /^[1-9][0-9]{5}$/.test(value.toString());
}
//校验是否为IPv6地址
export const isIPv6 = (str) => {
    return Boolean(str.match(/:/g)?str.match(/:/g).length<=7:false && /::/.test(str)?/^([\da-f]{1,4}(:|::)){1,6}[\da-f]{1,4}$/i.test(str):/^([\da-f]{1,4}:){7}[\da-f]{1,4}$/i.test(str));
}
//校验是否为邮箱地址
export const isEmail = (value) =>{
    return /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value);
}
// 校验是否为中国大陆手机号
export const isTel = (value) => {
    return /^1[3,4,5,6,7,8,9][0-9]{9}$/.test(value.toString());
}
//校验是否包含emoji表情
export const isEmojiCharacter = (value) => {
    value = String(value);
  for (let i = 0; i < value.length; i++) {
      const hs = value.charCodeAt(i);
      if (0xd800 <= hs && hs <= 0xdbff) {
          if (value.length > 1) {
              const ls = value.charCodeAt(i + 1);
              const uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
              if (0x1d000 <= uc && uc <= 0x1f77f) {
                  return true;
              }
          }
      } else if (value.length > 1) {
          const ls = value.charCodeAt(i + 1);
          if (ls == 0x20e3) {
              return true;
          }
      } else {
          if (0x2100 <= hs && hs <= 0x27ff) {
              return true;
          } else if (0x2B05 <= hs && hs <= 0x2b07) {
              return true;
          } else if (0x2934 <= hs && hs <= 0x2935) {
              return true;
          } else if (0x3297 <= hs && hs <= 0x3299) {
              return true;
          } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030
                  || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b
                  || hs == 0x2b50) {
              return true;
          }
      }
  }
    return false;
}
/**
 * 操作URL
 */
//获取URL参数列表
export const GetRequest = () => {
    let url = location.search;
    const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 后面的字符串取出来
    const paramsArr = paramsStr.split('&'); // 将字符串以 & 分割后存到数组中
    let paramsObj = {};
    // 将 params 存到对象中
    paramsArr.forEach(param => {
      if (/=/.test(param)) { // 处理有 value 的参数
        let [key, val] = param.split('='); // 分割 key 和 value
        val = decodeURIComponent(val); // 解码
        val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字
        if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key，则添加一个值
          paramsObj[key] = [].concat(paramsObj[key], val);
        } else { // 如果对象没有这个 key，创建 key 并设置值
          paramsObj[key] = val;
        }
      } else { // 处理没有 value 的参数
        paramsObj[param] = true;
      }
    })
    return paramsObj;
};
//检测URL是否有效
export const getUrlState = (URL) => {
    let xmlhttp = new ActiveXObject("microsoft.xmlhttp");
    xmlhttp.Open("GET", URL, false);
    try {
      xmlhttp.Send();
    } catch (e) {
    } finally {
      let result = xmlhttp.responseText;
      if (result) {
        if (xmlhttp.Status == 200) {
          return true;
        } else {
          return false;
        }
      } else {
        return false;
      }
    }
  }
  //键值对拼接成URL参数
  export const params2Url = (obj) => {
    let params = []
    for (let key in obj) {
      params.push(`${key}=${obj[key]}`);
    }
    return encodeURIComponent(params.join('&'))
}
//修改URL中的参数
export const replaceParamVal = (paramName, replaceWith) =>{
    const oUrl = location.href.toString();
    const re = eval('/('+ paramName+'=)([^&]*)/gi');
    location.href = oUrl.replace(re,paramName+'='+replaceWith);
    return location.href;
 }
 //删除URL中指定参数
 export const funcUrlDel = (name) => {
    const baseUrl = location.origin + location.pathname + "?";
    const query = location.search.substr(1);
    if (query.indexOf(name) > -1) {
      const obj = {};
      const arr = query.split("&");
      for (let i = 0; i < arr.length; i++) {
        arr[i] = arr[i].split("=");
        obj[arr[i][0]] = arr[i][1];
      }
      delete obj[name];
      return baseUrl + JSON.stringify(obj).replace(/[\"\{\}]/g,"").replace(/\:/g,"=").replace(/\,/g,"&");
    }
  }
  /**
   * 设备判断
   */
//   判断是移动还是PC设备
export const isMobile = () => {
    if ((navigator.userAgent.match(/(iPhone|iPod|Android|ios|iOS|iPad|Backerry|WebOS|Symbian|Windows Phone|Phone)/i))) {
          return 'mobile';
    }
    return 'desktop';
  }
  //判断是否是苹果还是安卓移动设备
  export const isAppleMobileDevice = () => {
    let reg = /iphone|ipod|ipad|Macintosh/i;
    return reg.test(navigator.userAgent.toLowerCase());
  }
  //判断是否是安卓移动设备
  export const isAndroidMobileDevice = () => {
    return /android/i.test(navigator.userAgent.toLowerCase());
  }
  //判断是Windows还是Mac系统
  export const osType = () => {
    const agent = navigator.userAgent.toLowerCase();
    const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
  	const isWindows = agent.indexOf("win64") >= 0 || agent.indexOf("wow64") >= 0 || agent.indexOf("win32") >= 0 || agent.indexOf("wow32") >= 0;
    if (isWindows) {
        return "windows";
    }
    if(isMac){
        return "mac";
    }
}
//判断是否是微信/QQ内置浏览器
export const broswer = () => {
    const ua = navigator.userAgent.toLowerCase();
    if (ua.match(/MicroMessenger/i) == "micromessenger") {
        return "weixin";
    } else if (ua.match(/QQ/i) == "qq") {
        return "QQ";
    }
    return false;
}
//浏览器型号和版本
export const getExplorerInfo = () => {
    let t = navigator.userAgent.toLowerCase();
    return 0 <= t.indexOf("msie") ? { //ie < 11
        type: "IE",
        version: Number(t.match(/msie ([\d]+)/)[1])
    } : !!t.match(/trident\/.+?rv:(([\d.]+))/) ? { // ie 11
        type: "IE",
        version: 11
    } : 0 <= t.indexOf("edge") ? {
        type: "Edge",
        version: Number(t.match(/edge\/([\d]+)/)[1])
    } : 0 <= t.indexOf("firefox") ? {
        type: "Firefox",
        version: Number(t.match(/firefox\/([\d]+)/)[1])
    } : 0 <= t.indexOf("chrome") ? {
        type: "Chrome",
        version: Number(t.match(/chrome\/([\d]+)/)[1])
    } : 0 <= t.indexOf("opera") ? {
        type: "Opera",
        version: Number(t.match(/opera.([\d]+)/)[1])
    } : 0 <= t.indexOf("Safari") ? {
        type: "Safari",
        version: Number(t.match(/version\/([\d]+)/)[1])
    } : {
        type: t,
        version: -1
    }
}
/**
 * 浏览器操作
 */
//滚动到页面顶部
export const scrollToTop = () => {
    const height = document.documentElement.scrollTop || document.body.scrollTop;
    if (height > 0) {
      window.requestAnimationFrame(scrollToTop);
      window.scrollTo(0, height - height / 8);
    }
  }
//   滚动到页面底部
export const scrollToBottom = () => {
    window.scrollTo(0, document.documentElement.clientHeight);  
  }
  //滚动到指定元素区域
  export const smoothScroll = (element) => {
    document.querySelector(element).scrollIntoView({
        behavior: 'smooth'
    });
};
//获取可视窗口高度
export const getClientHeight = () => {
    let clientHeight = 0;
    if (document.body.clientHeight && document.documentElement.clientHeight) {
        clientHeight = (document.body.clientHeight < document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight;
    }
    else {
        clientHeight = (document.body.clientHeight > document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight;
    }
    return clientHeight;
}
//获取可视窗口宽度
export const getPageViewWidth = () => {
    return (document.compatMode == "BackCompat" ? document.body : document.documentElement).clientWidth;
}
//打开浏览器全屏
export const toFullScreen = () => {
    let element = document.body;
    if (element.requestFullscreen) {
      element.requestFullscreen()
    } else if (element.mozRequestFullScreen) {
      element.mozRequestFullScreen()
    } else if (element.msRequestFullscreen) {
      element.msRequestFullscreen()
    } else if (element.webkitRequestFullscreen) {
      element.webkitRequestFullScreen()
    }
}
//退出浏览器全屏
export const exitFullscreen = () => {
    if (document.exitFullscreen) {
      document.exitFullscreen()
    } else if (document.msExitFullscreen) {
      document.msExitFullscreen()
    } else if (document.mozCancelFullScreen) {
      document.mozCancelFullScreen()
    } else if (document.webkitExitFullscreen) {
      document.webkitExitFullscreen()
    }
}
/**
 * 时间操作
 */
// 当前时间
export const nowTime = () => {
    const now = new Date();
    const year = now.getFullYear();
    const month = now.getMonth();
    const date = now.getDate() >= 10 ? now.getDate() : ('0' + now.getDate());
    const hour = now.getHours() >= 10 ? now.getHours() : ('0' + now.getHours());
    const miu = now.getMinutes() >= 10 ? now.getMinutes() : ('0' + now.getMinutes());
    const sec = now.getSeconds() >= 10 ? now.getSeconds() : ('0' + now.getSeconds());
    return +year + "年" + (month + 1) + "月" + date + "日 " + hour + ":" + miu + ":" + sec;
}
// 格式化时间
export const dateFormater = (formater, time) => {
    let date = time ? new Date(time) : new Date(),
        Y = date.getFullYear() + '',
        M = date.getMonth() + 1,
        D = date.getDate(),
        H = date.getHours(),
        m = date.getMinutes(),
        s = date.getSeconds();
    return formater.replace(/YYYY|yyyy/g, Y)
        .replace(/YY|yy/g, Y.substr(2, 2))
        .replace(/MM/g,(M<10 ? '0' : '') + M)
        .replace(/DD/g,(D<10 ? '0' : '') + D)
        .replace(/HH|hh/g,(H<10 ? '0' : '') + H)
        .replace(/mm/g,(m<10 ? '0' : '') + m)
        .replace(/ss/g,(s<10 ? '0' : '') + s)
}
// dateFormater('YYYY-MM-DD HH:mm:ss')
// dateFormater('YYYYMMDDHHmmss')
/**
 * JavaScript操作
 */
//阻止冒泡事件
export const stopPropagation = (e) => { 
    e = e || window.event; 
    if(e.stopPropagation) {    // W3C阻止冒泡方法 
        e.stopPropagation(); 
    } else { 
        e.cancelBubble = true; // IE阻止冒泡方法 
    } 
} 
//防抖函数
export const debounce = (fn, wait) => {
    let timer = null;
  
    return function() {
      let context = this,
          args = arguments;
  
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
  
      timer = setTimeout(() => {
        fn.apply(context, args);
      }, wait);
    };
  }
  //节流函数
  export const throttle = (fn, delay) => {
    let curTime = Date.now();
  
    return function() {
      let context = this,
          args = arguments,
          nowTime = Date.now();
  
      if (nowTime - curTime >= delay) {
        curTime = Date.now();
        return fn.apply(context, args);
      }
    };
  }
  //数据类型判断
  export const getType = (value) => {
    if (value === null) {
      return value + "";
    }
    // 判断数据是引用类型的情况
    if (typeof value === "object") {
      let valueClass = Object.prototype.toString.call(value),
        type = valueClass.split(" ")[1].split("");
      type.pop();
      return type.join("").toLowerCase();
    } else {
      // 判断数据是基本数据类型的情况和函数的情况
      return typeof value;
    }
  }
  //对象深拷贝
  export const deepClone = (obj, hash = new WeakMap()) => {
    // 日期对象直接返回一个新的日期对象
    if (obj instanceof Date){
        return new Date(obj);
    } 
    //正则对象直接返回一个新的正则对象     
    if (obj instanceof RegExp){
        return new RegExp(obj);     
    }
    //如果循环引用,就用 weakMap 来解决
    if (hash.has(obj)){
        return hash.get(obj);
    }
    // 获取对象所有自身属性的描述
    let allDesc = Object.getOwnPropertyDescriptors(obj);
    // 遍历传入参数所有键的特性
    let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
    
    hash.set(obj, cloneObj)
    for (let key of Reflect.ownKeys(obj)) { 
      if(typeof obj[key] === 'object' && obj[key] !== null){
          cloneObj[key] = deepClone(obj[key], hash);
      } else {
          cloneObj[key] = obj[key];
      }
    }
    return cloneObj
  }

  /**
   * lodash
   */
  